#! /usr/bin/php5
<?

$sOutDir = './Out' ;
$sXmiPath = 'lib.xmi' ;

$aCoder = new xmi2php($sXmiPath,$sOutDir) ;
$aCoder->Start() ;



class xmi2php
{
	private $sXmi ;
	private $sOutDir ;
	private $aXmlRoot = null ;
	
	// 类 或 接口
	private $arrClasses = array();
	
	// 关系
	private $arrGeneralizations = array() ;
	private $arrAbstractions = array() ;
	
	
	function xmi2php($sXmi,$sOutDir)
	{
		$this->sXmi = $sXmi ;
		$this->sOutDir = $sOutDir ;
	}
	
	function Start()
	{
		// 创建目录
		if( !file_exists($this->sOutDir) )
		{
			mkdir($this->sOutDir) ;
			echo "创建目录：{$this->sOutDir}\r\n" ;
		}


		// 开始分析 xmi
		$this->aXmlRoot = simplexml_load_file($this->sXmi);
		$arrPackages = $this->aXmlRoot->xpath('/XMI/XMI.content/UML:Model/UML:Namespace.ownedElement/UML:Package') ;
		foreach($arrPackages as $aPackageNode)
			$this->ProcessPackage($aPackageNode,$this->sOutDir.'/'.$aPackageNode['name']) ;
		
		// 创建  class  代码
		foreach($this->arrClasses as $arrClass)
		{
			$this->ProcessClass($arrClass['Node'],$arrClass['PackagePath'],$arrClass['DeclareKeyword']) ;
		}
		
		//print_r($this->arrGeneralizations) ;
		//print_r($this->arrAbstractions) ;
		//echo $this->GetParentClassName("UMLGeneralization.1999") ;
	}
	
	
	
	protected function ProcessPackage($aPackageNode,$sPackagePath)
	{
		if( !file_exists($sPackagePath) )
		{
			mkdir($sPackagePath) ;
			echo "创建目录：{$sPackagePath}\r\n" ;
		}
		
		// 类 和 接口
		$arrClasses = $aPackageNode->xpath('UML:Namespace.ownedElement/UML:Class') ;
		foreach($arrClasses as $aClassNode)
		{			
			if( empty($aClassNode['name']) )
				continue ;
			$sXmiId = $aClassNode['xmi.id'] ;
			echo "发现Class：{$aClassNode['name']} {$sXmiId}\r\n" ;
			$this->arrClasses[ "$sXmiId" ] = array(
						'Node' => $aClassNode ,
						'PackagePath' => $sPackagePath ,
						'DeclareKeyword' => 'class' ,
			) ;
			//print_r($aClassNode) ;
		}
		$arrInterfaces = $aPackageNode->xpath('UML:Namespace.ownedElement/UML:Interface') ;
		foreach($arrInterfaces as $aInterfaceNode)
		{			
			if( empty($aInterfaceNode['name']) )
				continue ;
			$sXmiId = $aInterfaceNode['xmi.id'] ;
			echo "发现Interface：{$aInterfaceNode['name']}\r\n" ;
			$this->arrClasses[ "{$aInterfaceNode['xmi.id']}" ] = array(
						'Node' => $aInterfaceNode ,
						'PackagePath' => $sPackagePath ,
						'DeclareKeyword' => 'interface' ,
			) ;
		}
		
		
		// 继承 extends
		$arrRelations = $aPackageNode->xpath('UML:Namespace.ownedElement/UML:Generalization') ;
		foreach($arrRelations as $aRelation)
		{			
			echo "关系：{$aRelation['xmi.id']}\r\n" ;			
			$this->arrGeneralizations[ "{$aRelation['xmi.id']}" ] = $aRelation['parent'] ;
		}
		
		// 实现 implements
		$arrRelations = $aPackageNode->xpath('UML:Namespace.ownedElement/UML:Abstraction') ;
		foreach($arrRelations as $aRelation)
		{			
			echo "关系：{$aRelation['xmi.id']}\r\n" ;			
			$this->arrAbstractions[ "{$aRelation['xmi.id']}" ] = $aRelation['supplier'] ;
		}
		
		
		// 递归 分析处理 子包
		$arrSubPackages = $aPackageNode->xpath('UML:Namespace.ownedElement/UML:Package') ;
		foreach($arrSubPackages as $aSubPackage)
			$this->ProcessPackage($aSubPackage,$sPackagePath.'/'.$aSubPackage['name']) ;

	}

	protected function ProcessClass($aClassNode,$sPackagePath,$sDeclareKeyword='class')
	{
		echo "正在处理 {$aClassNode['name']} ... \r\n" ;
		
		// 继承
		$sParentClass = $this->GetParentClassName($aClassNode['generalization']) ;
		
		// 实现
		$arrInterfaceClasses = array() ;
		if( $aClassNode['clientDependency'] )
		{
			$arrImplements = explode(' ',$aClassNode['clientDependency']) ;
			foreach($arrImplements as $sImplementXmiId)
			{
				$sName = $this->GetInterfaceNames($sImplementXmiId) ;
				if( $sName )
					$arrInterfaceClasses[] = $sName ;
			}
		}
		
		// 载入 inc.PATH.php 文件
		$sCode = "<?
/*-- Project Introduce --*/

include_once(dirname(__FILE__).'/inc.PATH.php') ;" ;

		// 导入 
		if($sParentClass)
			$sCode.= "

		foreach($arrInterfaceClasses as $sInterface)
			$sCode.= "

		
		// 申明类
		$sCode.= "


/**
 * What's this Class ?
 *
 * @author		alee
 * @access		".(preg_match("/^\_/",$aClassNode['name'])?'private':'public')."
 */
$sDeclareKeyword {$aClassNode['name']}"
		.($sParentClass? ' extends '.$sParentClass:'')
		.(count($arrInterfaceClasses)? ' implements '.implode(', ',$arrInterfaceClasses):'')."
{

" ;
		// 方法
		$arrMethods = $aClassNode->xpath('UML:Classifier.feature/UML:Operation') ;//print_r($arrMethods) ;
		foreach($arrMethods as $aMethodNode)
			$sCode.= $this->ProcessMethod($aMethodNode) ;
		
		
		// 属性
		$sCode.= "

	// 属性 ///////////////////////////////////////////////////////////////////////////////
" ;
		$arrAttributes = $aClassNode->xpath('UML:Classifier.feature/UML:Attribute') ;
		foreach($arrAttributes as $aAttributeNode)
			$sCode.= $this->ProcessAttribute($aAttributeNode) ;
		

		// 结束
		$sCode.= "

}
?>" ;

		file_put_contents("{$sPackagePath}/{$sDeclareKeyword}.{$aClassNode['name']}.php",$sCode) ;
	}

	protected function ProcessAttribute($aAttributeNode)
	{
		$sType = $this->arrClasses[ "{$aAttributeNode['type']}" ]['Node']['name']  ;
		
		// 申明类型
		$bStatic = false ;
		if($aAttributeNode['changeability']=='frozen')
			$sAccess = 'const' ;
		else
		{
			$sAccess = $aAttributeNode['visibility'] ;
			if($aAttributeNode['ownerScope']=='classifier')
				$bStatic = true ;
		}
		
		// 初始值
		$arrValues = $aAttributeNode->xpath('UML:Attribute.initialValue/UML:Expression') ;
		$sValue = count($arrValues)? ' = '.$arrValues[0]['body']: '' ;
			
		
		return "
	/**
	 * What's this Attribute ?
	 * 
	 * @access	{$sAccess}
	 * @var		{$sType}".($bStatic?"
	 * @static":'')."
	 */
	".($bStatic?'static ':'')."{$sAccess} {$aAttributeNode['name']}{$sValue} ;
" ;
	}

	protected function ProcessMethod($aMethodNode)
	{
		$arrClassInfo = $this->arrClasses[ "{$aMethodNode['owner']}" ] ;
		
		if($aMethodNode['ownerScope']=='classifier')
			$bStatic = true ;
		$sAccess = $aMethodNode['visibility'] ;
		$bAbstract = ($aMethodNode['isAbstract']=='true') ;
		$bNeedsBody = (!$bAbstract and $arrClassInfo['DeclareKeyword']!='interface') ;
		
		$sType = $this->arrClasses[ "{$aMethodNode['type']}" ]['Node']['name']  ;
		
		// 参数
		$arrParamNodes = $aMethodNode->xpath('UML:BehavioralFeature.parameter/UML:Parameter') ;
		$arrParamComments = array() ;
		$arrParamList = array() ;
		$sReturn = '@return	void' ;
		foreach($arrParamNodes as $aParamNode)
		{
			$sType = $this->arrClasses[ "{$aParamNode['type']}" ]['Node']['name'] ;
			if($aParamNode['kind']=='return')
				$sReturn = "@return	{$sType}" ;
			else
			{
				// 初始值
				$arrValues = $aParamNode->xpath('UML:Parameter.defaultValue/UML:Expression') ;
				$sDefaultValue = count($arrValues)? "={$arrValues[0]['body']}": '' ;
				
				$arrParamComments[] = "\r\n	 * @param	{$aParamNode['name']}{$sDefaultValue}	{$sType}	What's this Parameter ?" ;
				$arrParamList[] = "{$sType} {$aParamNode['name']}{$sDefaultValue}" ;
			}
		}
		
		$sParamComments = implode('',$arrParamComments) ;
		$sParamLists = implode(', ',$arrParamList) ;
				
		return "
	/**
	 * What's this Method ?
	 * 
	 * @access	{$sAccess}".$sParamComments.($bStatic?"
	 * @static":'')."
	 * {$sReturn}
	 */
	".($bAbstract?'abstract ':'').($bStatic?'static ':'')."{$sAccess} function {$aMethodNode['name']}( {$sParamLists} ) ".($bNeedsBody?"
	{
		// TODO
		// ... ...
	}":' ;')."


" ;
	}
	
	
	// 从一个 Generalization 关系的 XmiId 得到 Parent Class Name
	protected function GetParentClassName($sGeneralizationXmiId)
	{
		if( isset($this->arrGeneralizations[ "{$sGeneralizationXmiId}" ]) )
		{
			$sRel = $this->arrGeneralizations["{$sGeneralizationXmiId}"] ;
			return $this->arrClasses[ "{$sRel}" ]['Node']['name'] ;
		}
		else
			return '' ;
	}
	
	// 从一个 Abstraction 关系的 XmiId 得到 接口名稱
	protected function GetInterfaceNames($sAbstractionXmiId)
	{
		if( isset($this->arrAbstractions[ $sAbstractionXmiId ]) )
		{
			$sRel = $this->arrAbstractions["{$sAbstractionXmiId}"] ;
			return $this->arrClasses[ "{$sRel}" ]['Node']['name'] ;
		}
		else
			return '' ;
	}
}
?>